package org.hentai.bt;

import org.dom4j.DocumentException;
import org.hentai.bt.anno.ConnectDBMsg;
import org.hentai.bt.anno.EnableTableScan;
import org.hentai.bt.anno.Table;
import org.hentai.bt.err.NoAnnoException;
import org.hentai.bt.err.NoEnoughDbMsg;
import org.hentai.bt.scan.Scan;
import org.hentai.bt.scan.paramter.ScanParameter;
import org.hentai.bt.scan.table.ClassScan;

import java.io.IOException;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

public class DbConnectionMsg {

    private static Set<Class<?>> classSet;

    /**
     * 不填入类则默认以调用者为扫描对象
     */
    public static void crateTables() throws NoAnnoException, NoEnoughDbMsg, SQLException, ClassNotFoundException, IOException, DocumentException {


        String className = new Exception().getStackTrace()[1].getClassName();
        Class<?> clazz = Class.forName(className);
        crateTables(clazz);
    }

    /**
     * 以选择类来进行包扫描
     *
     * @param clazz 选择类
     */
    public static void crateTables(Class<?> clazz) throws NoAnnoException, NoEnoughDbMsg, SQLException, ClassNotFoundException, IOException, DocumentException {
        scanPackage(clazz);
        makeMigration();
        migrate();
    }

    private static EnableTableScan tableScan = null;
    protected static ConnectDBMsg dbMsg = null;

    /**
     * 初始化所需数据
     */
    private static void scanPackage(Class<?> clazz) throws NoAnnoException {

        if (clazz.isAnnotationPresent(EnableTableScan.class)) {
            tableScan = clazz.getAnnotation(EnableTableScan.class);
        }

        if (clazz.isAnnotationPresent(ConnectDBMsg.class)) {
            dbMsg = clazz.getAnnotation(ConnectDBMsg.class);
        }

        classSet = packageScan(clazz.getPackageName());
    }

    public static void setDbMsg(ConnectDBMsg msg) {
        dbMsg = msg;
    }

    public static ConnectDBMsg getDbMsg() {
        return dbMsg;
    }

    private static Set<Class<?>> packageScan(String packageName) throws NoAnnoException {
        if (tableScan == null) {
            throw new NoAnnoException();
        }

        String scanPaths = tableScan.scanPath();

        ScanParameter parameter = new ScanParameter();
        parameter.setPackageName(packageName);
        parameter.setClassPath(scanPaths);

        Scan scan = new ClassScan(parameter);

        Set<Class<?>> search = scan.search();

        return getTables(search);
    }

    private static Set<Class<?>> getTables(Set<Class<?>> allClass) {
        Set<Class<?>> tables = new HashSet<>();

        for (Class<?> table : allClass) {
            if (table.isAnnotationPresent(Table.class)) {
                tables.add(table);
            }
        }
        return tables;
    }

    private static void makeMigration() throws DocumentException, IOException {

        MakeMigrations migration = new MakeMigrations(classSet);
        migration.makeMigrations();
    }

    private static void migrate() throws NoEnoughDbMsg, SQLException, ClassNotFoundException, DocumentException, IOException {
        if (dbMsg == null) {
            throw new NoEnoughDbMsg();
        }

        Migrate migrate = new Migrate();
        migrate.migrate();
    }

}
